﻿/*
 * timedtrigger.cpp
 *
 *  Created on: 2018年2月18日
 *      Author: work
 */

#include <dm/export.hpp>

#define DM_API_MISC DM_API_EXPORT

#include <dm/timedtrigger.hpp>

namespace dm{

static const char* typeStr[] = {
		"禁止触发",
		"单次触发",
		"连续触发",

		"每秒触发",
		"每分钟触发",
		"每小时触发",
		"每天触发",
		"每月触发",
		"每年触发",

		"周一触发",
		"周二触发",
		"周三触发",
		"周四触发",
		"周五触发",
		"周六触发",
		"周日触发",

		"未定义"
};

CTimedTrigger::CTimedTrigger( const ETriggerType& type,const CDateTime& start,const dm::CTimeStamp& ):
		m_tt(type),m_startTime(start){
	m_lastTime.setInv();
}

CTimedTrigger::CTimedTrigger( const CTimedTrigger& trigger ):
		m_tt(trigger.m_tt),m_startTime(trigger.m_startTime),m_nextTime(trigger.m_nextTime){
	m_lastTime.setInv();
}

CTimedTrigger& CTimedTrigger::operator =( const CTimedTrigger& trigger ){
	m_tt = trigger.m_tt;
	m_startTime = trigger.m_startTime;
	m_nextTime = trigger.m_nextTime;
	m_lastTime.setInv();

	return *this;
}

/**
 * 复位触发器
 * 还原到初始状态
 * @param now
 */
void CTimedTrigger::reset( const dm::CTimeStamp& now ){
	m_lastTime.setInv();
	prepairNext(now);
}

/**
 * 检测是否可以触发
 * @param now
 * @return
 */
bool CTimedTrigger::ifTimeUp( const CTimeStamp& now ){
	if( m_tt==TtContinus ){
		m_lastTime = now;
		return true;
	}else	if( m_tt<=TtNone || m_tt>=TtUnknow )
		return false;
	else if( m_tt==TtSingle ){
		if( m_lastTime.isInv() ){
			if( m_nextTime<=now ){
				m_lastTime = now;
				return true;
			}
		}

		return false;
	}else	if( m_nextTime<=now ){
		m_lastTime = now;
		return true;
	}

	return false;
}

bool CTimedTrigger::prepairNext( const dm::CTimeStamp& now ){
	CDateTime dt(now);
	int days;

	switch( m_tt ){
	case TtSingle:
		if( m_lastTime.isInv() ){
			m_startTime.toTimeStamp(m_nextTime);
			return true;
		}

		break;
	case TtContinus:
		m_nextTime = now;
		return true;

	case TtSecondly:
		m_nextTime.setMseconds( m_startTime.msec() );
		if( now.mseconds()>m_startTime.msec() ){
			m_nextTime.setSeconds(now.seconds());
		}else{
			m_nextTime.setSeconds(now.seconds()+1);
		}

		return true;

	case TtMinutely:
		dt.setMsec(m_startTime.msec());
		dt.setSec(m_startTime.sec());
		dt.toTimeStamp(m_nextTime);
		if( m_nextTime<=now )
			m_nextTime.addSec(60);

		return true;
	case TtHourly:
		dt.setMsec(m_startTime.msec());
		dt.setSec(m_startTime.sec());
		dt.setMinute(m_startTime.minute());
		dt.toTimeStamp(m_nextTime);
		if( m_nextTime<=now )
			m_nextTime.addSec(3600);

		return true;
	case TtDaily:
		dt.setMsec(m_startTime.msec());
		dt.setSec(m_startTime.sec());
		dt.setMinute(m_startTime.minute());
		dt.setHour(m_startTime.hour());
		dt.toTimeStamp(m_nextTime);
		if( m_nextTime<=now )
			m_nextTime.addSec(3600*24l);

		return true;

	case TtMonthly:
		dt.setMsec(m_startTime.msec());
		dt.setSec(m_startTime.sec());
		dt.setMinute(m_startTime.minute());
		dt.setHour(m_startTime.hour());
		dt.setDay( m_startTime.day() );
		dt.toTimeStamp(m_nextTime);
		if( m_nextTime<=now ){
			if( dt.month()==12 ){
				dt.setMonth(1);
				dt.setYear(dt.year()+1);
			}else{
				dt.setMonth( dt.month()+1 );
			}
			dt.toTimeStamp(m_nextTime);
		}

		return true;
	case TtYearly:
		dt.setMsec(m_startTime.msec());
		dt.setSec(m_startTime.sec());
		dt.setMinute(m_startTime.minute());
		dt.setHour(m_startTime.hour());
		dt.setDay( m_startTime.day() );
		dt.setMonth(m_startTime.month());
		dt.toTimeStamp(m_nextTime);
		if( m_nextTime<=now ){
			dt.setYear(dt.year()+1);
			dt.toTimeStamp(m_nextTime);
		}

		return true;
	case TtMondays:
	case TtTuesdays:
	case TtWednesdays:
	case TtThursdays:
	case TtFridays:
	case TtSaturdays:
	case TtSundays:
		dt.setMsec(m_startTime.msec());
		dt.setSec(m_startTime.sec());
		dt.setMinute(m_startTime.minute());
		dt.setHour(m_startTime.hour());
		dt.toTimeStamp(m_nextTime);

		days = getDaysByWeek(dt.getWeekDay(),CDateTime::EWeekDay(m_tt-TtSundays));
		if( days>0 ){
			m_nextTime.addSec(days*24*3600l);
		}else if( m_nextTime<=now ){
			m_nextTime.addSec(7*24*3600l);
		}

		return true;
	default:
		return false;
	}

	return false;
}

const char* CTimedTrigger::typeString( const ETriggerType& type ){
	if( type<0 || type>=TtUnknow )
		return typeStr[TtUnknow-1];
	return typeStr[type];
}

int CTimedTrigger::getDaysByWeek( const CDateTime::EWeekDay& today,const CDateTime::EWeekDay& dday ){
	if( dday>=today )
		return dday - today;
	else
		return 7 + today - dday;
}

}
